package com.liik.game.mvc.tiled.object;

import com.liik.game.mvc.tiled.TiledGameModel;
import com.liik.game.util.Vector;

public abstract class MovableEntity extends Entity {

	public boolean isMoving;
	public Vector movingDirection = new Vector();
	public Vector lastLocation = new Vector();
	public float movementSpeed;

	public MovableEntity(float movementSpeed, float boundingRadius, int collisionHandlerPriority) {
		super(boundingRadius, collisionHandlerPriority);
		this.movementSpeed = movementSpeed;
	}

	protected abstract boolean canWalk(Tile tile);
	protected abstract boolean canMove();
	protected abstract boolean isBlockedByEntity(Entity entity);

	public void move(TiledGameModel gameModel, Vector target) {
		if (!canMove()) {
			return;
		}
		isMoving = true;
		lastLocation.set(this);
		boolean isLastLocationBlocked = isBlockedByOtherEntity(gameModel, lastLocation);
		movingDirection.setDirection(this, target);
		if (movingDirection.length() > movementSpeed) {
			movingDirection.normalize();
			movingDirection.mul(movementSpeed);
		}
		this.add(movingDirection);
		if (!isValidLocation(gameModel, this) || (isBlockedByOtherEntity(gameModel, this) && !isLastLocationBlocked)) {
			this.set(lastLocation);
			movingDirection.setDirection(this, target);
			movingDirection.y = 0;
			if (movingDirection.length() > movementSpeed) {
				movingDirection.normalize();
				movingDirection.mul(movementSpeed);
			}
			this.add(movingDirection);
			if (!isValidLocation(gameModel, this) || (isBlockedByOtherEntity(gameModel, this) && !isLastLocationBlocked)) {
				this.set(lastLocation);
				movingDirection.setDirection(this, target);
				movingDirection.x = 0;
				if (movingDirection.length() > movementSpeed) {
					movingDirection.normalize();
					movingDirection.mul(movementSpeed);
				}
				this.add(movingDirection);
				if (!isValidLocation(gameModel, this) || (isBlockedByOtherEntity(gameModel, this) && !isLastLocationBlocked)) {
					this.set(lastLocation);
					isMoving = false;
				}
			}
		}
	}

	private Vector distanceHelper = new Vector();
	
	protected boolean isBlockedByOtherEntity(TiledGameModel gameModel, Vector pos) {
		Entity[] allEntities = gameModel.getAllEntities();
		for (int i = 0; i < allEntities.length; ++i) {
			Entity entity = allEntities[i];
			if (entity == null || !entity.isActive()) {
				continue;
			}
			distanceHelper.setDirection(pos, entity);
			if (distanceHelper.length() < entity.boundingRadius + boundingRadius && isBlockedByEntity(entity)) {
				return true;
			}
		}
		return false;
	}

	protected boolean isValidLocation(TiledGameModel gameModel, Vector location) {
		return isValidLocation(gameModel, location.x, location.y) && isValidLocation(gameModel, location.x + boundingRadius, location.y + boundingRadius)
				&& isValidLocation(gameModel, location.x + boundingRadius, location.y - boundingRadius)
				&& isValidLocation(gameModel, location.x + boundingRadius, location.y)
				&& isValidLocation(gameModel, location.x - boundingRadius, location.y + boundingRadius)
				&& isValidLocation(gameModel, location.x - boundingRadius, location.y - boundingRadius)
				&& isValidLocation(gameModel, location.x - boundingRadius, location.y) && isValidLocation(gameModel, location.x, location.y + boundingRadius)
				&& isValidLocation(gameModel, location.x, location.y - boundingRadius);
	}

	private boolean isValidLocation(TiledGameModel gameModel, float x, float y) {
		Tile centerTile = gameModel.getTile(x, y);
		return centerTile != null && this.canWalk(centerTile);
	}
}
